package org.jeecg.app.modules.security.controller;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.CreditCodeUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.app.modules.security.model.LoginParam;
import org.jeecg.app.modules.security.model.LoginUser;
import org.jeecg.app.util.AsyncMethodUtils;
import org.jeecg.app.util.RandImageUtil;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.OrgTypeConstant;
import org.jeecg.common.util.*;
import org.jeecg.modules.share.umsEnterprise.entity.UmsEnterprise;
import org.jeecg.modules.share.umsEnterprise.service.IUmsEnterpriseService;
import org.jeecg.modules.share.umsEnterprise.service.impl.UmsEnterpriseServiceImpl;
import org.jeecg.modules.share.umsEnterpriseUser.entity.UmsEnterpriseUser;
import org.jeecg.modules.share.umsEnterpriseUser.service.IUmsEnterpriseUserService;
import org.jeecg.modules.share.umsExpert.entity.UmsExpert;
import org.jeecg.modules.share.umsExpert.service.IUmsExpertService;
import org.jeecg.modules.share.umsUser.entity.UmsUser;
import org.jeecg.modules.share.umsUser.service.IUmsUserService;
import org.jeecg.modules.system.entity.SysDict;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 登陆
 *
 * @author werdor
 */
@RestController
@RequestMapping("/auth")
@Slf4j
public class LoginController {

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    private static final String DEVICE = "app";

    private static final String LOGIN_TYPE_LOGIN = "login";

    private static final String LOGIN_TYPE_REGISTER = "register";

    private final IUmsUserService umsUserService;

    private final IUmsEnterpriseService umsEnterpriseService;

    private final IUmsExpertService umsExpertService;

    private final RedisUtil redisUtil;

    private final IUmsEnterpriseUserService umsEnterpriseUserService;

    @Autowired
    private AsyncMethodUtils asyncMethodUtils;


    public LoginController(IUmsUserService umsUserService, IUmsEnterpriseService umsEnterpriseService, IUmsExpertService umsExpertService, RedisUtil redisUtil, IUmsEnterpriseUserService umsEnterpriseUserService) {
        this.umsUserService = umsUserService;
        this.umsEnterpriseService = umsEnterpriseService;
        this.umsExpertService = umsExpertService;
        this.redisUtil = redisUtil;
        this.umsEnterpriseUserService = umsEnterpriseUserService;
    }

    /**
     * 登陆
     *
     * @param loginParam 登陆参数
     * @return
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result<JSONObject> login(@RequestBody LoginParam loginParam) {
        Result<JSONObject> result = new Result<>();
        String username = loginParam.getUsername();
        String password = loginParam.getPassword();
        String checkKey = loginParam.getCheckKey();

        //update-begin-author:taoyan date:20190828 for:校验验证码
        String captcha = loginParam.getCaptcha();
        if (captcha == null) {
            result.error500("验证码无效");
            return result;
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + DEVICE + LOGIN_TYPE_LOGIN + checkKey, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        //当进入登录页时，有一定几率出现验证码错误 #1714
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            result.error500("验证码错误");
            return result;
        }
        //update-end-author:taoyan date:20190828 for:校验验证码
        LambdaQueryWrapper<UmsUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UmsUser::getUsername, username);
        UmsUser umsUser = umsUserService.getOne(queryWrapper);
        result = umsUserService.checkUserIsEffective(umsUser);
        if (!result.isSuccess()) {
            return result;
        }
        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, umsUser.getSalt());
        String syspassword = umsUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            return result;
        }
        //用户登录信息
        userInfo(umsUser, result);

        return result;
    }


    /**
     * 生成图形验证码 ：有效
     *
     * @param response
     * @param key
     */
    @GetMapping(value = "/randomImage/{type}/{key}")
    public Result<String> randomImage(HttpServletResponse response, @PathVariable String key, @PathVariable String type) {
        Result<String> res = new Result<String>();
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCode + DEVICE + type + key, "utf-8");
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            res.error500("获取验证码出错" + e.getMessage());
            e.printStackTrace();
        }
        return res;
    }

    /**
     * 注册
     *
     * @param map
     * @return
     */
    @PostMapping("/register")
    public Result<JSONObject> userRegister(@RequestBody Map<String, Object> map) {
        Result<JSONObject> result = new Result<JSONObject>();
        //校验
        List<String> arr = Arrays.asList("userType","checkKey","captcha");
        DocumentUtils.verifyRequiredField(map, arr);
        String checkKey = Convert.toStr(map.get("checkKey"));

        //update-begin-author:taoyan date:20190828 for:校验验证码
        String captcha =  Convert.toStr(map.get("captcha"));
        if (captcha == null) {
            result.error500("验证码无效");
            return result;
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + DEVICE + LOGIN_TYPE_REGISTER + checkKey, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        //当进入登录页时，有一定几率出现验证码错误 #1714
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            result.error500("验证码错误");
            return result;
        }
        //获取用户名和密码
        String username = "";
        //1.根据不同用户类型查询是否能够注册
        result = umsUserService.checkUser(map);
        if (!result.isSuccess()) {
            return result;
        }
        //2.根据不同类型注册基本信息
        Integer userType = Convert.toInt(map.get("userType"));
        String salt = oConvertUtils.randomGen(8);
        //判断是否包含密码
        String password = "";
        String passwordEncode = "";
        if (map.containsKey("password")){
            password = Convert.toStr(map.get("password"));
        }
        String exId = "";
        //如果是企业
        if (OrgTypeConstant.ORG_TYPE_1.equals(userType)) {
            //map to bean
            UmsEnterprise enterprise = BeanUtil.fillBeanWithMap(map, new UmsEnterprise(), false);
            //校验
            boolean isCreditCode = CreditCodeUtil.isCreditCode(enterprise.getCreditCode());
            if (!isCreditCode) {
                result.error500("该社会信用代码有误，请重新填写");
            }
            username = enterprise.getEmail();
            passwordEncode = PasswordUtil.encrypt(username, password, salt);
            umsEnterpriseService.save(enterprise);
            //获取拓展ID
            exId = enterprise.getId();
        }
        if (OrgTypeConstant.ORG_TYPE_2.equals(userType)) {
            UmsExpert umsExpert = BeanUtil.fillBeanWithMap(map, new UmsExpert(), false);
            //用户名和专家手机号统一
            umsExpert.setPhone(username);
            umsExpert.setStatus(CommonConstant.STATUS_DISABLE);
            umsExpertService.save(umsExpert);
            //获取拓展ID
            exId = umsExpert.getId();
        }
        if (OrgTypeConstant.ORG_TYPE_4.equals(userType)){
            UmsEnterpriseUser umsEnterpriseUser = BeanUtil.fillBeanWithMap(map, new UmsEnterpriseUser(), false);
            username =umsEnterpriseUser.getEmail();
            long count =  umsEnterpriseUserService.count(Wrappers.<UmsEnterpriseUser>lambdaQuery().eq(UmsEnterpriseUser::getEmail,username));
            if (count<=0){
                umsEnterpriseUserService.save(umsEnterpriseUser);
                //获取拓展ID
                exId = umsEnterpriseUser.getId();
            }
        }
        try {
            log.info("生成密码: {}", password);
            if (org.apache.commons.lang3.StringUtils.isNoneEmpty(exId) && org.apache.commons.lang3.StringUtils.isNoneEmpty(password)){
                umsUserService.saveUsr(salt, username, passwordEncode, userType, exId, password);
            }else {
                String uid =  umsUserService.saveUsrNoPaw(username,userType,exId);
                //发送token
                String token = SaTempUtil.createToken(uid, 60*60*24);
                asyncMethodUtils.sendHtmlEmail(username,"常德市科技服务信息平台项目申请人注册通知","<div id=\"mailContentContainer\" class=\"qmbox qm_con_body_content qqmail_webmail_only\" style=\"opacity: 1;\">"+map.get("name")+"先生/女士：<br><br><br><br>您已注册为常德市科技管理信息系统公共服务平台项目申请人，请通过以下链接继续完成注册，并登录系统完善个人信息以完成激活，激活成功后，您可以使用系统更多其他功能。<br><br>请注意：电子邮箱就是登录账号。<br><br>链接：<a href=\"http://192.168.66.118:8080/#/pages/index/index?token="+token+"\" rel=\"noopener\" target=\"_blank\">http://192.168.66.118:8080/#/pages/index/index?token="+token+"</a><br><br><br><br>如果您无法直接通过点击访问以上链接，请复制该链接，粘贴至浏览器软件的地址栏进行访问。<br><br>系统相关问题请联系系统技术支持：可致电16673602736 ； <style type=\"text/css\">.qmbox style, .qmbox script, .qmbox head, .qmbox link, .qmbox meta {display: none !important;}</style></div>");
            }
            result.success("注册成功");
        } catch (Exception e) {
            result.error500("注册失败");
        }

        return result;
    }

    /**
     * 根据临时token获取信息
     */
    @GetMapping("/userinfoByToken")
    public Result<?> userinfoByToken(@RequestParam(name = "token", required = true) String token) {
        // 解析 token 获取 value，并转换为指定类型
        String value = SaTempUtil.parseToken(token,String.class);
        if (StringUtils.isEmpty(value)){
            return Result.error("当前链接已失效");
        }
        UmsUser umsUser =  umsUserService.getById(value);
        UmsEnterpriseUser umsEnterpriseUser = umsEnterpriseUserService.getById(umsUser.getExtendId());
        Map<String ,Object > map = BeanUtil.beanToMap(umsUser,true,true);
        map.put("extendInfo",umsEnterpriseUser);
        return Result.OK("获取成功", map);
    }

    /**
     * 根据临时token获取信息
     */
    @PutMapping("/userinfoByToken")
    public Result<?> userinfoByTokenEdit(@RequestBody Map<String,Object> map) {
        // 解析 token 获取 value，并转换为指定类型
        String token = Convert.toStr(map.get("token"));
        String password = Convert.toStr(map.get("password"));
        String value = SaTempUtil.parseToken(token,String.class);

        if (StringUtils.isEmpty(value)){
            return Result.error("当前链接已失效");
        }
        UmsUser umsUser =  umsUserService.getById(value);
        // 密码加密加盐
        String salt = oConvertUtils.randomGen(8);
        umsUser.setSalt(salt);
        String passwordEncode = PasswordUtil.encrypt(umsUser.getUsername(),password, salt);
        umsUser.setPassword(passwordEncode);
        umsUserService.updateById(umsUser);
        // 删除指定 token
        SaTempUtil.deleteToken(token);

        return Result.OK("修改成功");
    }

    /**
     * 获取当前登陆人信息
     */
    @AutoLog(value = "获取当前登陆人信息")
    @GetMapping("/userinfo")
    public Result<?> info() {
        Map<String, Object> umsUser = (Map<String, Object>) StpUtil.getSession().get("umsUser");
        return Result.OK("获取成功", umsUser);
    }

    /**
     * 退出登录
     *
     * @return
     */
    @AutoLog(value = "退出登录")
    @RequestMapping(value = "/logout")
    public Result<Object> logout() {
        Map<String, Object> umsUser = (Map<String, Object>) StpUtil.getSession().get("umsUser");
        log.info(" 用户名:  " + umsUser.get("username") + ",退出成功！ ");
        StpUtil.logout();
        return Result.ok("退出登录成功！");
    }


    /**
     * 用户信息
     *
     * @param umsUser
     * @param result
     * @return
     */
    private Result<JSONObject> userInfo(UmsUser umsUser, Result<JSONObject> result) {
        JSONObject obj = new JSONObject();
        LoginUser loginUser = new LoginUser();
        //复制属性 去除掉一些信息不显示
        BeanUtil.copyProperties(umsUser, loginUser);
        Map<String, Object> map = BeanUtil.beanToMap(loginUser);
        if (OrgTypeConstant.ORG_TYPE_1.equals(umsUser.getType())) {
            UmsEnterprise umsEnterprise = umsEnterpriseService.getById(umsUser.getExtendId());
            map.put("extendInfo", umsEnterprise);
        }
        if (OrgTypeConstant.ORG_TYPE_2.equals(umsUser.getType())) {
            UmsExpert umsExpert = umsExpertService.getById(umsUser.getExtendId());
            //手机号、身份证号脱敏
            umsExpert.setPhone(DesensitizedUtil.mobilePhone(umsExpert.getPhone()));
            umsExpert.setIdCard(DesensitizedUtil.idCardNum(umsExpert.getIdCard(), 1, 2));
            map.put("extendInfo", umsExpert);
        }
        if (OrgTypeConstant.ORG_TYPE_4.equals(umsUser.getType())) {
            UmsEnterpriseUser umsEnterpriseUser = umsEnterpriseUserService.getById(umsUser.getExtendId());
            UmsEnterprise umsEnterprise = umsEnterpriseService.getById(umsEnterpriseUser.getOrgId());
            umsEnterpriseUser.setUmsEnterprise(umsEnterprise);
            map.put("extendInfo", umsEnterpriseUser);
        }
        StpUtil.login(umsUser.getId());
        StpUtil.getSession().set("umsUser", map);
        SaTokenInfo saTokenInfo = StpUtil.getTokenInfo();
        obj.put("token", saTokenInfo);
        obj.put("userInfo", map);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

//    public static void main(String[] args) {
//        String username = "2194232501";
//        String password = "123456";
//        String salt = "FZ4mrVxi";
//        String userpassword = PasswordUtil.encrypt(username, password, salt);
//        System.out.println(userpassword);
//    }
}